package scene

import (
	"fmt"
	"learn-opengl/camera"
	. "learn-opengl/util"
	"learn-opengl/object/clound"
	"learn-opengl/object/hugeBlock"
	"learn-opengl/opengl/shader"
	"math"

	"github.com/go-gl/mathgl/mgl32"
)

// 管理整个场景
// 包括 地形生成  云朵生成
type Scene struct {
	// 管理地形---使用map方便索引 --- block 大小15*15 位置从 右底下脚开始
	// id 为 x*100000 + y  100000/15 ~ 10000
	hugeBlocksMap map[int]*hugeBlock.HugeBlock
	cloundMap map[int]*clound.Clound
	// 
	BlockShader *shader.Shader
	player *camera.Camera
}

func NewScene(shader *shader.Shader,player *camera.Camera) *Scene {
	return &Scene{
		hugeBlocksMap: make(map[int]*hugeBlock.HugeBlock),
		cloundMap: make(map[int]*clound.Clound),
		BlockShader: shader,
		player: player,
	}
}

// 根据玩家位置来更新场景
func (s *Scene) Update() {
	// 设置为玩家 初始坐标为 （0，10，0）
	// 每向x轴移动15个单位就代表要渲染更新x轴的方块了
	// 每项z轴移动15个单位就代表要渲染z轴的方块了
	// 生成当前方块
	// 找到自己最近的中心点 --- 》 
	pos := s.player.GetPos()
	// fmt.Println(pos)
	fx := math.Round(float64(pos[0]))
	fz := math.Round(float64(pos[2]))
	x := int(math.Floor(float64(fx)/15))
	z := int(math.Floor(float64(fz)/15))
	// fmt.Println(x,z)
	// 生成对于的hugeB
	for i:=-4;i<=4;i++ {
		for j:=-4;j<=4;j++ {
			nx := x + i
			nz := z + j
			id := nx*100000 + nz
			if h,ok := s.hugeBlocksMap[id];ok {
				h.Draw(s.player,s.BlockShader)
			} else {
				h := hugeBlock.NewHugeBlock(IV3{nx*15,-10,nz*15},1)
				h.Draw(s.player,s.BlockShader)
				s.hugeBlocksMap[id] = h
			}
		}
	}

	// 生成云朵
	x = int(pos[0]) - (int(pos[0])%50)
	z = int(pos[2]) - (int(pos[2])%50)
	id := x*100000 + z
	if c,ok := s.cloundMap[id];ok {
		c.Draw(s.player,s.BlockShader)
	} else {
		clound := clound.NewClound(pos.Add(mgl32.Vec3{0,0,0}))
		s.cloundMap[id] = clound
		clound.Draw(s.player,s.BlockShader)
	}
}	

func (s *Scene) HasBlock(pos IV3) bool {
	
	h,ok := s.hugeBlocksMap[pos.Block()]
	if !ok {
		fmt.Println(pos,pos.Block())
		panic("HasBlock error！")
	}
	_,ok = h.Blocks[pos]
	if !ok {
		return false
	}
	return true
}


func (s *Scene) CheckCollid(pos mgl32.Vec3) (mgl32.Vec3,bool) {
	x,y,z := pos[0],pos[1],pos[2]
	// 利用四舍五入求出块中心
	nx,ny,nz := float32(math.Round(float64(x))),float32(math.Round(float64(y))),float32(math.Round(float64(z)))
	// fmt.Println(nx,ny,nz)
	const pad = 0.25

	head := IV3{int(nx),int(ny),int(nz)}
	foot := head.Down()
	
	stop := false
	for _, b := range []IV3{foot,head} {
		if s.HasBlock(b.Left()) && x<nx {
			x = nx
		}
		if s.HasBlock(b.Right()) && x>nx {
			x = nx
		}
		if s.HasBlock(b.Down()) && y<ny  {
			y = ny
			stop = true
		}
		if s.HasBlock(b.Top()) && y>ny  {
			y = ny
			stop = true
		}
		if s.HasBlock(b.Back()) && z > nz {
			z = nz
		}
		if s.HasBlock(b.Front()) && z < nz {
			z = nz
		}
	}
	return mgl32.Vec3{x, y, z}, stop
}


func (s *Scene) BuildBlock(pos IV3,kind int) {
	s.hugeBlocksMap[pos.Block()].Blocks[pos] = kind
}